
雖然 Vue 透過模板幫助我們處理了大部分的DOM 操作,但在某些情況下,仍然需要手動操作 DOM。例如,在使用第三方套件(如 Bootstrap 的 Modal)時,或者需要調用像video.play()和video.pause()這類的原生 Web API 時,我們必須直接與 DOM 元素進行交互。此時,可以使用ref屬性為DOM 元素設置標記,以便方便地引用並手動操作這些元素。
觀察Bootstrap的Modal 組件可以發現,若要使用 JavaScript 來控制 Modal,需要先創建一個 Bootstrap Modal 的實例,並將對應的 Modal 元素 ID 傳遞給這個實例。完成這一步後,就可以透過 modal.show()或modal.hide()這樣的方法來控制 Modal 的開啟和關閉。
原生的 Boostrap Modal 使用流程說明:
Boostrap實例綁定對應顯示的 Modal DOM 元素。show()和hide()方法。👉 Boostrap Modal 純 javaScript 寫法實作連結
HTML:
<div class="modal" tabindex="-1" role="dialog" id="modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button id="saveButton" type="button" class="btn btn-primary">Save changes</button>
<button id="closeButton" type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
javascript:
const myModal = new bootstrap.Modal(document.getElementById("modal"));
// 開啟 Modal 按鈕
document.querySelector("#openModal").addEventListener("click", function () {
myModal.show();
});
// Modal 儲存按鈕
document.querySelector("#saveButton").addEventListener("click", function () {
myModal.hide();
});
// Modal 關閉按鈕
document.querySelector("#closeButton").addEventListener("click", function () {
myModal.hide();
});
接著我們將上面的控制方式改成使用 Vue 進行管控。
👉 Vue3 Options API Bootstrap Modal ref 實作連結
document.getElementById("modal")的部分取得的 DOM 元素,改成透過ref的方式取得。v-on綁定click事件,點擊的時候觸發對應的方法show()和hide()方法。Vue Template:
<div id="app">
<div class="p-4">
<button @click="openModal" id="openModal" type="button" class="btn btn-primary">打開 modal</button>
<div class="modal" tabindex="-1" role="dialog" ref="modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button @click="closeModal" id="saveButton" type="button" class="btn btn-primary">Save changes</button>
<button @click="closeModal" id="closeButton" type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
javascript:
const rootComponent = {
data() {
return {
myModal: null
};
},
methods: {
// 開啟 Modal
openModal() {
this.myModal.show();
},
// 關閉 Modal
closeModal() {
this.myModal.hide();
}
},
mounted() {
this.myModal = new bootstrap.Modal(this.$refs.modal);
}
};
⭐ 預設ref對象會是undefined如果需要讀取到其對應的DOM 元素需要在mouted模板渲染完成之後的階段。
除了上述與第三方套件搭配的案例外,在使用像video這類的原生 HTML 標籤時,也經常需要使用其內建的 Web API,例如:play()和pause()方法來控制播放行為。在這些情況下,可以利用 Vue 的ref屬性來標記這些 DOM 元素,以便進行手動控制和操作。
👉 Vue3 Options API HTML video tag with ref 實作連結
Vue Template:
<video src="https://www.w3schools.com/html/mov_bbb.mp4" ref='video'></video>
<div class="btn-group" role="group" aria-label="Basic example">
<button @click="play" type="button" class="btn btn-secondary">play</button>
<button @click="pause" type="button" class="btn btn-secondary">pause</button>
<button @click="reset" type="button" class="btn btn-secondary">reset</button>
javascript:
const rootComponent = {
data() {
return {
videoInstance: null
};
},
methods: {
play() {
this.videoInstance.play();
},
pause() {
this.videoInstance.pause();
},
reset() {
this.videoInstance.pause();
this.videoInstance.currentTime = 0;
}
},
mounted() {
this.videoInstance = this.$refs.video;
}
};
在 Vue 中,當ref與v-for 指令一起使用時,Vue 會自動將生成的 DOM 元素存儲在一個陣列中。可以透過this.$refs訪問這些元素。
👉 Vue3 Options API v-for 搭配 ref 陣列實作連結
Vue Template:
<ul>
<li v-for="item in productList" :key="item" ref="items">{{ item }}</li>
</ul>
javascript:
const app = createApp({
data() {
return {
productList: ["Apple", "Orange", "Banana"]
};
}
mounted() {
console.log("this.items", this.$refs.items);
}
});
⭐ 無法保證綁定陣列中ref 屬性的順序與原始陣列數據的順序一致
可以透過綁定一個動態 ref 屬性,在每次模板更新時將該ref傳入到一個函數中進行處理。如果綁定的元素被銷毀,傳入函數的參數值將會自動變為null。
流程說明:
動態綁定的 ref 屬性,自動將焦點聚焦到該輸入框,達到 focus() 效果。👉 Vue3 Options API ref 動態綁定方法(method)實作連結

Vue Template:
<div v-if="isShowAccount" class="input-group">
<label for="inputAccount">使用者帳號:</label>
<input id="inputAccount" type="text" :ref="setRef">
</div>
<button @click="register" type="button">切換顯示使用者帳號輸入框</button>
javascript:
methods: {
setRef(ref) {
// ref 是動態傳入的屬性
if (ref) {
this.$nextTick(() => {
ref.focus();
});
}
},
register() {
this.isShowAccount = !this.isShowAccount;
}
}
...略
當ref 屬性被應用在 HTML 元素上時,它會標記並引用實際的HTML DOM 元素;而當ref 屬性被應用在子組件上時,ref 屬性則會引用該子組件的實例。透過這個ref 屬性,可以直接訪問子組件的內部數據和方法。不過,過度使用ref 屬性來操作子組件的資料和行為,可能會導致資料流混亂,需要謹慎使用。
流程說明:

👉 Vue3 Options API ref 取得組件實體內數據及方法實作連結
父組件 Vue Template:
<child-component ref="child"></child-component>
<p>取得子組件的響應式變數值:{{ RootCount }}</p>
<button @click="getChildCount" type="button">取得子組件的響應試變數值</button>
<button @click="addNum" type="button">使用子組件 addNum 增加子組件 childCount 變數值</button>
⭐ 【 取得子組件的響應試變數值 】按鈕可以取得子組件childCount當前變數值。
⭐ 【 使用子組件 addNum 讓子組件 childCount 變數值 + 1 】按鈕可以取得子組件addNum 函數,並且將子組件 childCount 變數值 + 1。
父組件 javascript:
const rootComponent = {
data() {
return {
RootCount: 0
};
},
methods: {
// 取得子組件數據 childCount
getChildCount() {
this.RootCount = this.$refs.child.childCount;
},
// 使用子組件內的 addNum 方法
addNum() {
this.$refs.child.addNum();
}
},
components: {
childComponent
}
};
子組件 javascript:
const childComponent = {
template: "#childComponent",
data() {
return {
// 紀錄計數器當前數字
childCount: 0
};
},
methods: {
// 將變數 childCount + 1
addNum() {
this.childCount += 1;
}
}
};
如果希望限制子組件實例中哪些數據和方法可以被外部訪問,可以在子組件中使用expose 選項,來控制外層透過ref 屬性能夠讀取的範圍。
以上面的案例為例,可以使用expose選項來限制只有addNum方法能被外部通過 ref 屬性訪問,而子組件的數據childCount則無法被外部讀取。
當呼叫根組件getChildCount方法試圖取得子組件childCount參數的時候,會回傳undefined。
👉 Vue3 Options API ref 取得組件實體內數據及方法(搭配 expose 限制)實作連結
javascript:
const childComponent = {
expose: ["addNum"],
template: "#childComponent",
data() {
return {
// 紀錄計數器當前數字
childCount: 0
};
},
methods: {
// 將變數 childCount + 1
addNum() {
this.childCount += 1;
}
}
};
HTML 元素進行操作時,可以使用 Vue 的ref 屬性來標記對應的HTML DOM 元素,方便與第三方套件或 Web API 結合使用。v-for生成多個元素時,可以使用ref 屬性來將這些元素存儲為一個陣列,便於後續進行批次操作。函數的方式動態綁定 ref,在需要時對原生 HTML 元素進行操作。當綁定的元素或組件被銷毀時,函數中的ref 參數會自動變為null。ref 綁定子組件實例,直接訪問子組件內部的變數或調用其方法。需要注意的是,這種操作可能會導致資料流的混亂,因此應謹慎使用。ref 屬性訪問內部數據和方法的範圍,可以使用expose 參數來定義哪些數據和方法可以被外部訪問。